package com.zhome.gateway.web;

import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.LoggerContext;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternUtils;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.util.ClassUtils;
import org.springframework.util.SystemPropertyUtils;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.*;

/**
 * 修改日志级别
 * @author cuiyh9
 * @date 2020/5/9
 */
@RestController
@RequestMapping("/log")
@Slf4j
public class LogController {

    @Autowired
    private ResourceLoader resourceLoader;

    private ResourcePatternResolver resolver = ResourcePatternUtils.getResourcePatternResolver(resourceLoader);

    private MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(resourceLoader);

    private static final String PACKAGE_PATH = "com.zhome.gateway";

    private static final String LOG_CHANGE_LEVEL_TEMPLETE = "%s " +
            "<a href='/log/level/%s/DEBUG' target='_blank'>DEBUG</a>&nbsp;&nbsp;" +
            "<a href='/log/level/%s/INFO' target='_blank'>INFO</a>&nbsp;&nbsp;" +
            "<a href='/log/level/%s/WARN' target='_blank'>WARN</a>&nbsp;&nbsp;" +
            "<a href='/log/level/%s/ERROR' target='_blank'>ERROR</a><br/>";

    @RequestMapping("/level/{className}/{logLevel}")
    public String  changeLevel(@PathVariable("className") String className,
                      @PathVariable("logLevel") String logLevel) {
        try {
            LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
            loggerContext.getLogger(className).setLevel(Level.valueOf(logLevel));
        } catch (Exception e) {
            log.error("动态修改日志级别出错", e);
            return "fail";
        }
        return "success";
    }

    @RequestMapping("/level/test")
    public String testLogLevel() {
        StringBuilder sb = new StringBuilder();
        if (log.isDebugEnabled()) {
            sb.append("I am debug! <br/>");
        }

        if (log.isInfoEnabled()) {
            sb.append("I am info! <br/>");
        }

        if (log.isWarnEnabled()) {
            sb.append("I am warn! <br/>");
        }

        if (log.isErrorEnabled()) {
            sb.append("I am error! <br/>");
        }
        return sb.toString();
    }

    @RequestMapping("/list/class")
    public  String listClass() throws Exception {
        Set<String> classSet = new TreeSet<>();
        String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX
                .concat(ClassUtils
                        .convertClassNameToResourcePath(SystemPropertyUtils.resolvePlaceholders(PACKAGE_PATH))
                        .concat("/**/*.class"));
        Resource[] resources = resolver.getResources(packageSearchPath);
        MetadataReader metadataReader = null;
        for (Resource resource : resources) {
            if (!resource.isReadable()) {
                continue;
            }
            metadataReader = metadataReaderFactory.getMetadataReader(resource);
            if (metadataReader.getClassMetadata().isConcrete()) {
                // 当类型不是抽象类或接口在添加到集合
                classSet.add(metadataReader.getClassMetadata().getClassName());
            }
        }
        StringBuilder sb = new StringBuilder();
        if (classSet == null) {
            return "";
        }
        classSet.forEach( className -> {
            sb.append(String.format(LOG_CHANGE_LEVEL_TEMPLETE, className, className, className, className, className));
        });
        return sb.toString();
    }


}
